package org.javaboy.shiro.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.javaboy.shiro.realm.MyRealm;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * WebConfig 相当于 spring-servlet.xml
 */
@Configuration
@ComponentScan(basePackages = "org.javaboy.shiro")
@EnableWebMvc
@PropertySource("classpath:db.properties")
public class WebConfig implements EnvironmentAware, WebMvcConfigurer {
    private Environment env;

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }

    @Bean
    DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setUsername(env.getProperty("db.username"));
        ds.setPassword(env.getProperty("db.password"));
        ds.setUrl(env.getProperty("db.url"));
        return ds;
    }

    @Bean
    SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setTypeAliasesPackage("org.javaboy.shiro.model");
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:org/javaboy/shiro/mapper/*.xml"));
        return factoryBean;
    }

    @Bean
    MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("org.javaboy.shiro.mapper");
        configurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
        return configurer;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("/");
    }

    @Bean
    SecurityManager securityManager(MyRealm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        return securityManager;
    }

    /**
     * Shiro 中的认证功能，主要是通过过滤器来实现的。
     * 这里实际上就是去配置 shiro 中的过滤器的
     *
     * @return
     */
    @Bean
    ShiroFilterFactoryBean shiroFilterFactoryBean(MyRealm myRealm) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager(myRealm));
        //配置登录页面
        bean.setLoginUrl("/login.html");
        //这里要有序
        Map<String, String> urlMaps = new LinkedHashMap<>();
        // /doLogin 这个接口使用 anon 过滤器，即这个接口可以匿名访问
        urlMaps.put("/doLogin", "anon");
        urlMaps.put("/login.html", "anon");
        //其他路径，必须登录之后才能访问
        urlMaps.put("/**", "authc");
        //这个是配置拦截规则的
        bean.setFilterChainDefinitionMap(urlMaps);
        return bean;
    }
}
